/**
**********************************************************************
* @file     main.c
* @brief    对文件的简要说明
* @details  对文件的详细说明
* @author   jcai
* @date     2022-05-04 15:12:18
* @copyright Copyright &copy; 2022 wy1107412334@163.com All rights reserved
* @version  v0.0.1
*
* \n Email:  wy1107412334@163.com
* \n Blog:   None
* \n Github: https://github.com/wy1107412334
* \n Gitee:  https://gitee.com/git.git1107412334.com
*
**********************************************************************
* @note
* None.
**********************************************************************
* @attention
* None.
**********************************************************************
@verbatim
@endverbatim
**********************************************************************
* @par 历史记录
* 1. v0.0.1: jcai, 2022-05-04 15:12:18
*   - 首次编写
*
*<center>Copyright &copy; 2022 wy1107412334@163.com All rights reserved</center>
**********************************************************************
*/

/* 头文件导入区 --------------------------------------------------- */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_video.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_events.h>
#include <SDL/SDL_timer.h>
#include <SDL/SDL_keysym.h>
#include <SDL/SDL_keyboard.h>


// 保存程序信息的文件名
#define FILE_NAME "save_game"

typedef struct
{
    int startTicks;
    int pausedTicks;
    int paused;
    int started;
} Timer_t;

typedef struct
{
    int x, y;
    int xVel, yVel;
} Dot_t;

// 窗口属性
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

// 帧速率
const int FRAMES_PER_SECOND = 20;

// 圆点的大小
const int DOT_WIDTH = 20;
const int DOT_HEIGHT = 20;

// 将要使用的表面
SDL_Surface *dot = NULL;
SDL_Surface *message= NULL;
SDL_Surface *screen = NULL;

// 事件结构体
SDL_Event event;

// 使用的字体
TTF_Font *font;
// 字体颜色
SDL_Color textColor = {0x77, 0x77, 0x77};


SDL_Surface *load_image(const char *file)
{
    SDL_Surface *loadedImage = NULL;
    SDL_Surface *optimizedImage = NULL;

    // 通过 SDL_imag 模块加载图片
    loadedImage = IMG_Load(file);
    if (!loadedImage)   return NULL;

    optimizedImage = SDL_DisplayFormat(loadedImage);
    SDL_FreeSurface(loadedImage);
    if (optimizedImage)
    {
        // 映射关键色
        uint32_t keycolor = SDL_MapRGB(optimizedImage->format, 0, 0xff, 0xff);
        // 将所有颜色为 RGB(0x00, 0xff, 0xff) 的像素设为透明
        SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, keycolor);
    }

    return optimizedImage;
}

void apply_surface(int x, int y, SDL_Surface *src, SDL_Surface *dst)
{
    SDL_Rect offset;

    offset.x = x;
    offset.y = y;

    SDL_BlitSurface(src, NULL, dst, &offset);
}

int init()
{
    if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
        return -1;

    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP,
                              SDL_SWSURFACE);
    if (!screen)
    {
        SDL_Quit();
        return -2;
    }

    if (TTF_Init() == -1)
    {
        SDL_Quit();
        return -3;
    }

    SDL_WM_SetCaption("Move the Dot", NULL);

    // 给窗口背景填充白色
    SDL_FillRect(screen, &screen->clip_rect,
                 SDL_MapRGB(screen->format, 0xff, 0xff, 0xff));

    return 0;
}

int load_files(Dot_t *dt, uint32_t *pbg)
{
    FILE *pf;

    // 加载背景图片
    dot = load_image("dot.png");
    if (!dot) return -1;

    font = TTF_OpenFont("lazy.ttf", 42);
    if (!font)
    {
        SDL_FreeSurface(dot);
        return -2;
    }

    pf = fopen(FILE_NAME, "r");
    if (pf)
    {
        int xoffset, yoffset;
        char level[20] = {0};

        fscanf(pf, "%d %d\n", &xoffset, &yoffset);
        dt->x = xoffset;
        dt->y = yoffset;
        if ((dt->x < 0) || (dt->x > (SCREEN_WIDTH - DOT_WIDTH)))
        {
            SDL_FreeSurface(dot);
            TTF_CloseFont(font);
            return -3;
        }
        if ((dt->y < 0) || (dt->y > (SCREEN_HEIGHT - DOT_HEIGHT)))
        {
            SDL_FreeSurface(dot);
            TTF_CloseFont(font);
            return -4;
        }

        fscanf(pf, "%s\n", level);
        if (!strncmp(level, "White_Level", strlen("White_Level")))
            *pbg = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
        else if (!strncmp(level, "Red_Level", strlen("Red_Level")))
            *pbg = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
        else if (!strncmp(level, "Green_Level", strlen("Green_Level")))
            *pbg = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
        else if (!strncmp(level, "Blue_Level", strlen("Blue_Level")))
            *pbg = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);

        fclose(pf);
    }
    else
    {
    }

    return 0;
}

void clean_up(Dot_t *dt, uint32_t *pbg)
{
    FILE *pf;

    SDL_FreeSurface(dot);
    SDL_FreeSurface(message);

    TTF_CloseFont(font);
    TTF_Quit();

    pf = fopen(FILE_NAME, "w+");
    if (pf)
    {
        uint8_t r,g,b;
        char *str;

        fprintf(pf, "%d %d\n", dt->x, dt->y);

        SDL_GetRGB(*pbg, screen->format, &r, &g, &b);
        if ((r == 0xff) && (g == 0xff) && (b == 0xff))
            str = "White_Level";
        else if (r == 0xff)
            str = "Red_Level";
        else if (g == 0xff)
            str = "Green_Level";
        else if (b == 0xff)
            str = "Blue_Level";
        else
            str = "White_Level";
        fprintf(pf, "%s\n", str);

        fclose(pf);
    }
    else
    {
    }

    SDL_Quit();
}


void dot_init(Dot_t *dt)
{
    dt->x = 0;
    dt->y = 0;

    dt->xVel = 0;
    dt->yVel = 0;
}
void dot_handle_input(Dot_t *dt)
{
    if (event.type == SDL_KEYDOWN)
    {
        switch (event.key.keysym.sym)
        {
        case SDLK_UP: dt->yVel -= DOT_HEIGHT / 2; break;
        case SDLK_DOWN: dt->yVel += DOT_HEIGHT / 2; break;
        case SDLK_LEFT: dt->xVel -= DOT_WIDTH / 2; break;
        case SDLK_RIGHT: dt->xVel += DOT_WIDTH / 2; break;
        default: break;
        }
    }
    else if (event.type == SDL_KEYUP)
    {
        switch (event.key.keysym.sym)
        {
        case SDLK_UP: dt->yVel += DOT_HEIGHT / 2; break;
        case SDLK_DOWN: dt->yVel -= DOT_HEIGHT / 2; break;
        case SDLK_LEFT: dt->xVel += DOT_WIDTH / 2; break;
        case SDLK_RIGHT: dt->xVel -= DOT_WIDTH / 2; break;
        default: break;
        }
    }
}
void dot_move(Dot_t *dt)
{
    dt->x += dt->xVel;
    if ((dt->x < 0) || ((dt->x + DOT_WIDTH) > SCREEN_WIDTH))
        dt->x -= dt->xVel;

    dt->y += dt->yVel;
    if ((dt->y < 0) || ((dt->y + DOT_HEIGHT) > SCREEN_HEIGHT))
        dt->y -= dt->yVel;
}
void dot_show(const Dot_t *dt)
{
    apply_surface(dt->x, dt->y, dot, screen);
}


void timer_init(Timer_t *tm)
{
    tm->startTicks = 0;
    tm->pausedTicks = 0;
    tm->paused = 0;
    tm->started = 0;
}
void timer_start(Timer_t *tm)
{
    tm->started = 1;
    tm->paused = 0;

    tm->startTicks = SDL_GetTicks();
}
void timer_stop(Timer_t *tm)
{
    tm->started = 0;
}
void timer_pause(Timer_t *tm)
{
    if (tm->started && !tm->paused)
    {
        tm->paused = 1;
        tm->pausedTicks = SDL_GetTicks() - tm->startTicks;
    }
}
void timer_unpause(Timer_t *tm)
{
    if (tm->paused)
    {
        tm->paused = 0;

        tm->startTicks = SDL_GetTicks() - tm->pausedTicks;
        tm->pausedTicks = 0;
    }
}
int timer_get_ticks(Timer_t *tm)
{
    if (tm->started)
    {
        if (tm->paused)
            return tm->pausedTicks;
        else
            return SDL_GetTicks() - tm->startTicks;
    }
    return 0;
}
int timer_is_started(Timer_t *tm)
{
    return tm->started;
}
int timer_is_paused(Timer_t *tm)
{
    return tm->paused;
}


/**
**********************************************************************
* @brief    简要说明
* @details  详细说明
* @param    none
* @param[in]     a: 该参数用于输入
* @param[in,out] b: 该参数用于输入和输出
* @param[out]    c: 该参数用于输出
* @retval  none
* @retval  0 函数成功
* @retval  1 函数失败
* @return  返回0成功；否则失败
* @note    none
*/
int main(int argc, char *argv[])
{
    Timer_t fps;
    Dot_t dt;
    uint32_t background;
    int quit = 0;

    if (init() != 0)
    {
        fprintf(stderr, "SDL初始化失败\n");
        return EXIT_FAILURE;
    }

    dot_init(&dt);
    timer_init(&fps);
    background = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);

    if (load_files(&dt, &background) != 0)
    {
        fprintf(stderr, "SDL加载 background.png 失败\n");
        return EXIT_FAILURE;
    }

    message = TTF_RenderText_Solid(font, "Press 1/2/3/4 key.", textColor);
    if (!message)
    {
        fprintf(stderr, "生成文字表 失败\n");
        return EXIT_FAILURE;
    }

    while (!quit)
    {
        timer_start(&fps);

        // 处理SDL的事件
        while (SDL_PollEvent(&event))
        {
            dot_handle_input(&dt);

            if (event.type == SDL_KEYDOWN)
            {
                switch (event.key.keysym.sym)
                {
                case SDLK_1:
                    background = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
                    break;
                case SDLK_2:
                    background = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
                    break;
                case SDLK_3:
                    background = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
                    break;
                case SDLK_4:
                    background = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
                    break;
                default: break;
                }
            }

            // 如果用户点击了窗口右上角的关闭按钮
            if (event.type == SDL_QUIT)
            {
                quit = 1;
                printf("处理退出事件\n");
            }
        }

        // 更新背景
        SDL_FillRect(screen, &screen->clip_rect, background);
        apply_surface((SCREEN_WIDTH - message->w) / 2,
                      SCREEN_HEIGHT - message->h,
                      message,
                      screen);

        // 移动圆点
        dot_move(&dt);
        // 显示圆点
        dot_show(&dt);

        // 更新窗口
        if (SDL_Flip(screen) == -1)
        {
            fprintf(stderr, "SDL更新窗口失败\n");
            break;
        }

        // 控制帧速率
        if (timer_get_ticks(&fps) < (1000 / FRAMES_PER_SECOND))
            SDL_Delay((1000 / FRAMES_PER_SECOND) - timer_get_ticks(&fps));
    }

    clean_up(&dt, &background);

    return 0;
}


/***  Copyright (C) 2022 wy1107412334@163.com All rights reserved ***/
/****************************** END OF FILE *************************/

